
#include "Bag.h"

extern IGame* g_pGame;

// 工具函数
const char* GetBagTableName(UI08 byBagType)
{
	switch(byBagType)
	{
	case BAG_TYPE_EQUIP:
		return PROP_TABLE_EQUIP;
		break;
	case BAG_TYPE_BAG:
		return PROP_TABLE_BAG;
		break;
	case BAG_TYPE_STORE:
		return PROP_TABLE_STORE;
		break;
	default:
		assert(false);
		return 0;
	}
}

const char* GetBagUpdateTableName(UI08 byBagType)
{
	switch(byBagType)
	{
	case BAG_TYPE_EQUIP:
		return PROP_TABLE_EQUIP_SLOT_UPDATE;
		break;
	case BAG_TYPE_BAG:
		return PROP_TABLE_BAG_SLOT_UPDATE;
		break;
	case BAG_TYPE_STORE:
		return PROP_TABLE_STORE_SLOT_UPDATE;
		break;
	default:
		assert(false);
		return 0;
	}
}

int GetMaxStack(DWORD dwEntry)
{
	if(!g_pGame)
		return 0;

	int nMaxStack = g_pGame->GetPropInt(dwEntry, "stack");
	return nMaxStack;
}

// max can own in bag
int GetMaxNum(DWORD dwEntry)
{
	if(!g_pGame)
		return 0;

	int nMaxNum = g_pGame->GetPropInt(dwEntry, "max_num");
	return nMaxNum;
}

int GetItemType(DWORD dwEntry)
{
	if(!g_pGame)
		return 0;

	int nType = g_pGame->GetPropInt(dwEntry, "type");
	return nType;
}

int GetItemEquipType(DWORD dwEntry)
{
	if(!g_pGame)
		return 0;

	int nEquipType = g_pGame->GetPropInt(dwEntry, "equip_type");
	return nEquipType;
}

bool GetBagFreeSlotCountCB(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if (!row)
	{
		( * (int*) param ) ++;
	}

	return true;
}

int GetBagFreeSlotCount(IGame* pScene, UI32 self, UI08 byBagType)
{
	int freecount = 0;

	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == NULL)
		return 0;

	pScene->TraverseTable(self, strTabName, GetBagFreeSlotCountCB, &freecount, true);
	return freecount;
}

struct FindItemCountStruct
{
	DWORD	dwEntry; 			//物品entry
	UI08	byIncludeBind;		//包括绑定
	UI08	byIncludeTimeout;	//是否包括失效的物品
	DWORD	dwItemCount;		//数量

	FindItemCountStruct() : dwItemCount(0){}
};

bool GetBagItemCountCB(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if (!row)
		return true;
	if (!param)
		return false;

	FindItemCountStruct* pStruct = (FindItemCountStruct*)param;
	if(!pStruct->byIncludeBind)
	{
		int bindType = 0;
		if ( colCount >= bind_i && row->varList[bind_i].Type() == VARTYPE_INT)
		{
			bindType = row->varList[bind_i].IntVal();
		}

		if(bindType)
			return true;
	}

	if(!pStruct->byIncludeTimeout)
	{
		int nUneffectTime = 0;
		if ( colCount >= uneffecttime_i && row->varList[uneffecttime_i].Type() == VARTYPE_INT )
		{
			nUneffectTime = row->varList[uneffecttime_i].IntVal();
		}

		time_t now;
		::time(&now);
		if(now >= nUneffectTime)
			return true;
	}

	if ( pStruct->dwEntry == row->varList[entry_i].IntVal() )
	{
		// 加上物品数量
		pStruct->dwItemCount += row->varList[stack_i].IntVal();
	}

	return true;
}

int GetBagItemCount(IGame* pScene, UI32 self, UI08 byBagType, UI16 wEntry, UI08 byIncludeBind, UI08 byIncludeTimeout)
{
	FindItemCountStruct ent;
	ent.dwEntry 	= wEntry;
	ent.byIncludeBind = byIncludeBind;
	ent.byIncludeTimeout = byIncludeTimeout;
	ent.dwItemCount = 0;

	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == NULL)
		return 0;

	pScene->TraverseTable(self, strTabName, GetBagItemCountCB, &ent, true);
	return ent.dwItemCount;
}

int get_bag_max_slot(IGame* pScene, UI32 self, UI08 byBagType)
{
	switch( byBagType )
	{
	case BAG_TYPE_EQUIP:
		return MAX_EQUIP_SLOT_COUNT;
	case BAG_TYPE_BAG:
		{
			UI08 byExtendBagCount = pScene->GetPropInt(self, PROP_EXTEND_BAG_COUNT);
			int maxslot = (byExtendBagCount+BAG_INIT_COUNT)*BAG_VER_NUMBER*BAG_COL_NUMBER;
			return maxslot;
		}
	case BAG_TYPE_STORE:
		{
			UI08 byExtendStoreCount = pScene->GetPropInt(self, PROP_EXTEND_STORE_COUNT);
			int maxslot = (byExtendStoreCount+BAG_INIT_COUNT)*BAG_VER_NUMBER*BAG_COL_NUMBER;
			return maxslot;
		}
	default:
		break;
	}

	return 0;
}

int get_max_slot(IGame* pScene, UI32 self, UI08 byBagType)
{
	UI08 byMaxEquipSlot = 	get_bag_max_slot(pScene, self, BAG_TYPE_EQUIP);
	UI08 byMaxBagSlot = 	get_bag_max_slot(pScene, self, BAG_TYPE_BAG);
	UI08 byMaxStoreSlot = 	get_bag_max_slot(pScene, self, BAG_TYPE_STORE);

	return byMaxEquipSlot + byMaxBagSlot + byMaxStoreSlot;
}

int CalcEquipProperties(IGame* pScene, UI32 self, UI08 bySlot, UI08 byOnEquip)
{
	if(byOnEquip)
	{
		//装备上来
	}
	else
	{
		//卸载装备
	}

	return 1;
}


void SetSlotUpdate(IGame* pScene, UI32 self, UI08 byBagType, UI08 bySlot)
{
	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == NULL)
		return ;

	pScene->SetRowInt(self, strTabName, bySlot, "changed", 1);
}

void ClearSlotUpdate(IGame* pScene, UI32 self, UI08 byBagType)
{
	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == NULL)
		return ;

	UI08 byMaxSlot = get_bag_max_slot(pScene, self, byBagType);
	for(int i=0; i<byMaxSlot; i++)
	{
		pScene->SetRowInt(self, strTabName, i, 0, 0);
	}
}

bool CanOverlay(IGame* pScene, UI32 self, UI08 byBagType, UI08 bySlot, Item& item)
{
	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == NULL)
		return false;
	if(pScene->GetRowInt(self, strTabName, bySlot, entry_i) != item.dwEntry)
		return false;
	if(pScene->GetRowInt(self, strTabName, bySlot, bind_i) != item.byBind)
		return false;
	if(pScene->GetRowInt(self, strTabName, bySlot, uneffecttime_i) != item.dwUneffectTime)
		return false;

	return true;
}

bool CanOverlay(CVarRow* & row, Item& item)
{
	if(row->varList[entry_i].IntVal() != item.dwEntry)
		return false;
	if(row->varList[bind_i].IntVal() != item.byBind)
		return false;
	if(row->varList[uneffecttime_i].IntVal() != item.dwUneffectTime)
		return false;
	return true;
}

bool CanOverlay(Item& item1, Item& item2)
{
	if(item1.dwEntry != item2.dwEntry)
		return false;
	if(item1.byBind != item2.byBind)
			return false;
	if(item1.dwUneffectTime != item2.dwUneffectTime)
			return false;
	return true;
}


void SetItemData(IGame* pScene, UI32 self, const char* strTabName, int slot, Item* pItem)
{
	CMsgTyped newItem;
	newItem.SetString(pItem->strGuid.c_str());
	newItem.SetInt(pItem->dwEntry);
	newItem.SetInt(pItem->bySlot);
	newItem.SetInt(pItem->wStack);
	newItem.SetInt(pItem->byBind);
	newItem.SetInt(pItem->byQuality);
	newItem.SetInt(pItem->dwUneffectTime);
	newItem.SetString(pItem->strJson.c_str());

	pScene->SetRow(self, strTabName, (int)slot, newItem);
}

void GetItemData(IGame* pScene, UI32 self, const char* strTabName, int slot, Item& item)
{
	item.strGuid 	= pScene->GetRowString(self, strTabName, slot, guid_i);
	item.dwEntry 	= pScene->GetRowInt(self, strTabName, slot, entry_i);
	item.bySlot 	= pScene->GetRowInt(self, strTabName, slot, slot_i);
	item.byBind 	= pScene->GetRowInt(self, strTabName, slot, bind_i);
	item.wStack		= pScene->GetRowInt(self, strTabName, slot, stack_i);
	item.byQuality	= pScene->GetRowInt(self, strTabName, slot, quality_i);
	item.dwUneffectTime = pScene->GetRowInt(self, strTabName, slot, uneffecttime_i);
}

void GetItemData(CVarRow* & row, Item& item)
{
	item.strGuid	= row->varList[guid_i].StringVal();
	item.dwEntry 	= row->varList[entry_i].IntVal();
	item.bySlot 	= row->varList[slot_i].IntVal();
	item.byBind 	= row->varList[bind_i].IntVal();
	item.wStack		= row->varList[stack_i].IntVal();
	item.byQuality	= row->varList[quality_i].IntVal();
	item.dwUneffectTime = row->varList[uneffecttime_i].IntVal();
	item.strJson 	= row->varList[uneffecttime_i].IntVal();
}

void SerialItemData(Item& item, CMsgTyped& packet)
{
	packet.SetString(item.strGuid.c_str());
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//logic
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// 背包初始化
void OnInitBag(IGame* pScene, UI32 self)
{
	if (pScene->AddPropInt(self, PROP_EXTEND_BAG_COUNT, 0))
	{
		pScene->SetPropInt(self, PROP_EXTEND_BAG_COUNT, 0);
	}

	if (pScene->AddPropInt(self, PROP_EXTEND_STORE_COUNT, 0))
	{
		pScene->SetPropInt(self, PROP_EXTEND_STORE_COUNT, 0);
	}

	// 装备
	UI08 byMaxEquipSlot = get_bag_max_slot(pScene, self, BAG_TYPE_EQUIP);
	if (pScene->CreateTable(self, PROP_TABLE_EQUIP, MEM_TAB_FIELDS_STR_EQUIP,
			byMaxEquipSlot, byMaxEquipSlot))
	{
		for (int i=0; i < byMaxEquipSlot; i++)
		{
			pScene->ClearRow(self, PROP_TABLE_EQUIP, i);
		}
	}

	// 背包
	UI08 byMaxBagSlot = get_bag_max_slot(pScene, self, BAG_TYPE_BAG);
	if (pScene->CreateTable(self, PROP_TABLE_BAG, MEM_TAB_FIELDS_STR_BAG,
			byMaxBagSlot, byMaxBagSlot))
	{
		for (int i=0; i < byMaxBagSlot; i++)
		{
			pScene->ClearRow(self, PROP_TABLE_BAG, i);
		}
	}

	// 仓库
	UI08 byMaxStoreSlot = get_bag_max_slot(pScene, self, BAG_TYPE_STORE);
	if (pScene->CreateTable(self, PROP_TABLE_STORE, MEM_TAB_FIELDS_STR_STORE,
			byMaxStoreSlot, byMaxStoreSlot))
	{
		for (int i=0; i < byMaxStoreSlot; i++)
		{
			pScene->ClearRow(self, PROP_TABLE_STORE, i);
		}
	}

	// 更新用的slot表
	if(pScene->CreateTable(self, PROP_TABLE_EQUIP_SLOT_UPDATE, "int:changed",
			byMaxEquipSlot, byMaxEquipSlot))
	{
		for (int i=0; i < byMaxEquipSlot; i++)
		{
			pScene->ClearRow(self, PROP_TABLE_EQUIP_SLOT_UPDATE, i);
		}
	}

	if(pScene->CreateTable(self, PROP_TABLE_BAG_SLOT_UPDATE, "int:changed",
			byMaxBagSlot, byMaxBagSlot))
	{
		for (int i=0; i < byMaxBagSlot; i++)
		{
			pScene->ClearRow(self, PROP_TABLE_BAG_SLOT_UPDATE, i);
		}
	}

	if(pScene->CreateTable(self, PROP_TABLE_STORE_SLOT_UPDATE, "int:changed",
			byMaxStoreSlot, byMaxStoreSlot))
	{
		for (int i=0; i < byMaxStoreSlot; i++)
		{
			pScene->ClearRow(self, PROP_TABLE_STORE_SLOT_UPDATE, i);
		}
	}

	pScene->SetSaveTable(self, PROP_TABLE_EQUIP, 	true);
	pScene->SetSaveTable(self, PROP_TABLE_BAG, 		true);
	pScene->SetSaveTable(self, PROP_TABLE_STORE, 	true);
	pScene->SetSaveTable(self, PROP_TABLE_EQUIP_SLOT_UPDATE, 	false);
	pScene->SetSaveTable(self, PROP_TABLE_BAG_SLOT_UPDATE, 		false);
	pScene->SetSaveTable(self, PROP_TABLE_STORE_SLOT_UPDATE, 	false);


	// 计算装备的属性加成
	for(int i=0; i<MAX_EQUIP_SLOT_COUNT; i++)
	{
		CalcEquipProperties(pScene, self, i, 1);
	}

	// 发送物品初始化包
	SendBagItemsPacket(pScene, self, BAG_TYPE_EQUIP);
	SendBagItemsPacket(pScene, self, BAG_TYPE_BAG);
	SendBagItemsPacket(pScene, self, BAG_TYPE_STORE);

}

// 背包销毁
void OnUnInitBag(IGame* pScene, UI32 self)
{

}

// 向客户端发送背包数据
void SendBagItemsPacket(IGame* pScene, UI32 self, UI08 byBagType)
{
	std::vector<Item> vecItem;
	FillItem(pScene, self, byBagType, vecItem);
	if(vecItem.size() > 0)
	{
		CMsgTyped packet;
		packet.SetInt(byBagType);
		packet.SetInt(vecItem.size());
		for(int i=0; i<vecItem.size(); i++)
		{
			Item& item = vecItem[i];
			SerialItemData(item, packet);
		}

		pScene->Custom(self, 1, &packet);
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// fill vector
bool FillItemCB(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if(!param)
		return false;
	if(!row)
		return true;

	std::vector<Item>* vecItems = (std::vector<Item>*)param;

	Item item;
	GetItemData(row, item);
	vecItems->push_back(item);

	return true;
}


void FillItem(IGame* pScene, UI32 self, UI08 byBagType, std::vector<Item>& vecItems)
{
	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == NULL)
		return ;

	pScene->TraverseTable(self, strTabName, FillItemCB, &vecItems, true);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 能不能储存物品
struct canStoreItemStruct
{
	Item*  pItem;
	IGame* pScene;

	canStoreItemStruct() : pScene(0) {}
};

bool CanStoreItemCB_Overlay(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if(!row)
		return true;
	if(!param)
		return false;

	canStoreItemStruct* pStruct = (canStoreItemStruct*)param;
	if(!CanOverlay(row, *pStruct->pItem))
		return true;
	int nMaxStack = GetMaxStack(pStruct->pItem->dwEntry);
	if( nMaxStack <= row->varList[stack_i].IntVal())
		return true;

	int nRemainCount = nMaxStack - row->varList[stack_i].IntVal();
	if(nRemainCount > pStruct->pItem->wStack)
	{
		pStruct->pItem->wStack = 0;
	}
	else
	{
		pStruct->pItem->wStack -= (nMaxStack - nRemainCount);
	}

	return (pStruct->pItem->wStack != 0);
}

bool CanStoreItem(IGame* pScene, UI32 self, Item& item)
{
	canStoreItemStruct itemStruct;
	itemStruct.pItem = &item;
	itemStruct.pScene = pScene;

	pScene->TraverseTable(self, PROP_TABLE_BAG, CanStoreItemCB_Overlay, &itemStruct, true);

	if(item.wStack == 0)
		return false;

	if(GetBagItemCount(pScene, self, BAG_TYPE_BAG, item.dwEntry) + item.wStack > GetMaxNum(item.dwEntry))
		return false;

	int nMaxStack = GetMaxStack(item.dwEntry);

	int nNeedSlot = item.wStack / nMaxStack;
	if(item.wStack % nMaxStack)
		nNeedSlot++;

	if(GetBagFreeSlotCount(pScene, self, BAG_TYPE_BAG) < nNeedSlot)
		return false;

	return true;
}

struct storeItemStruct
{
	Item item;
	IGame* pScene;
	UI32   self;

	storeItemStruct() : pScene(0), self(0) {}
};

bool StoreItemCB_Overlay(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	// overlay
	if(!row)
		return true;
	if(!param)
		return false;

	storeItemStruct* pItemStruct = (storeItemStruct*)param;
	if(!CanOverlay(row, pItemStruct->item))
		return true;
	int nMaxStack = GetMaxStack(pItemStruct->item.dwEntry);
	if( nMaxStack <= row->varList[stack_i].IntVal())
		return true;

	int nRemainCount = nMaxStack - row->varList[stack_i].IntVal();
	if( nRemainCount >= pItemStruct->item.wStack)
	{
		row->varList[stack_i].SetInt(row->varList[stack_i].IntVal()+pItemStruct->item.wStack);
		pItemStruct->item.wStack = 0;
	}
	else
	{
		row->varList[stack_i].SetInt(nMaxStack);
		pItemStruct->item.wStack -= nRemainCount;
	}

	SetSlotUpdate(pItemStruct->pScene, pItemStruct->self, BAG_TYPE_BAG, index);

	return (pItemStruct->item.wStack != 0);
}

bool StoreItemCB_New(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	//empty slot
	if(row)
		return true;
	if(!param)
		return false;

	storeItemStruct* pItemStruct = (storeItemStruct*)param;
	int nMaxStack = GetMaxStack(pItemStruct->item.dwEntry);

	Item item = pItemStruct->item;
	item.wStack = nMaxStack > pItemStruct->item.wStack ? pItemStruct->item.wStack:nMaxStack;

	pItemStruct->item.wStack -= item.wStack;

	SetItemData(pItemStruct->pScene, pItemStruct->self, PROP_TABLE_BAG, index, &item);

	SetSlotUpdate(pItemStruct->pScene, pItemStruct->self, BAG_TYPE_BAG, index);

	return pItemStruct->item.wStack != 0;
}

int StoreItem(IGame* pScene, UI32 self, Item& item)
{
	// 尝试把物品放进背包
	// 此接口仅用于从外部存储物品到背包
	// 查看背包空间
	//if(!CanStoreItem(pScene, self, item))
		//return 0;

	storeItemStruct itemstruct;
	itemstruct.item = item;
	itemstruct.pScene = pScene;
	itemstruct.self = self;

	pScene->TraverseTable(self, PROP_TABLE_BAG, StoreItemCB_Overlay, &itemstruct, false);

	if(itemstruct.item.wStack > 0)
	{
		pScene->TraverseTable(self, PROP_TABLE_BAG, StoreItemCB_New, &itemstruct, false);
	}

	return 1;
}

bool CanStoreItems(IGame* pScene, UI32 self, std::vector<Item>& vecItems)
{
	int nFreeSlot = GetBagFreeSlotCount(pScene, self, BAG_TYPE_BAG);

	int nNeedSlot = 0;
	for(std::vector<Item>::iterator it = vecItems.begin(); it != vecItems.end(); it++)
	{
		Item& item = *it;

		if(GetBagItemCount(pScene, self, BAG_TYPE_BAG, item.dwEntry) + item.wStack > GetMaxNum(item.dwEntry))
			return false;

		int nMaxStack = GetMaxStack(item.dwEntry);
		nNeedSlot += item.wStack / nMaxStack;
		if(item.wStack % nMaxStack != 0)
			nNeedSlot++;
	}

	return nFreeSlot > nNeedSlot;
}

int StoreItems(IGame* pScene, UI32 self, std::vector<Item>& vecItems)
{
	//if(!CanStoreItems(pScene, self, lstItems))
		//return 0;

	for(std::vector<Item>::iterator it = vecItems.begin(); it != vecItems.end(); it++)
	{
		Item& item = *it;
		/*int freeSlot = pScene->FindFirstEmptyRow(self, PROP_TABLE_BAG);
		assert(freeSlot != -1);
		SetItemData(pScene, self, PROP_TABLE_BAG, freeSlot, &item);
		SetSlotUpdate(pScene, self, BAG_TYPE_BAG, freeSlot);*/

		StoreItem(pScene, self, item);
	}

	return 1;
}


int MoveItem(IGame* pScene, UI32 self, UI08 bySrcBag, UI08 bySrcSlot, UI08 byTarBag, UI08 byTarSlot)
{
	if(bySrcBag == BAG_TYPE_EQUIP || byTarBag == BAG_TYPE_EQUIP)
		return 0;


}

int SplitItem(IGame* pScene, UI32 self, UI08 byBag, UI08 bySlot, UI16 wSplitCount)
{
	const char* strTabName = GetBagTableName(byBag);
	if(strTabName == NULL)
		return 0;
	if(bySlot >= pScene->GetMaxRowCount(self, strTabName))
		return 0;

	int nDestSlot = pScene->FindFirstEmptyRow(self, strTabName);
	if(nDestSlot == -1)
		return 0;

	int nOldCount = pScene->GetRowInt(self, strTabName, nDestSlot, stack_i);
	if(nOldCount <= wSplitCount)
		return 0;

	pScene->SetRowInt(self, strTabName, nDestSlot, stack_i, nOldCount - wSplitCount);

	Item item;
	GetItemData(pScene, self, strTabName, bySlot, item);
	item.bySlot = nDestSlot;
	item.wStack = wSplitCount;
	SetItemData(pScene, self, strTabName, nDestSlot, &item);

	SetSlotUpdate(pScene, self, byBag, bySlot);
	SetSlotUpdate(pScene, self, byBag, nDestSlot);

	return 1;
}

int DeleteItem(IGame* pScene, UI32 self, UI08 byBag, UI08 bySlot)
{
    const char* strTabName = GetBagTableName(byBag);
	if(strTabName == NULL)
		return 0;
	if(bySlot >= pScene->GetMaxRowCount(self, strTabName))
		return 0;

    pScene->DeleteRow(self, strTabName, bySlot);

    SetSlotUpdate(pScene, self, byBag, bySlot);

	return 1;
}

struct storeDeleteItembyEntry
{
	IGame* 	pScene;
	UI08	byBagType;
	UI32	self;
	DWORD 	dwEntry;
	int  	nCount;
	UI08 	byIncludeBind;
	UI08 	byIncludeTimeout;

	storeDeleteItembyEntry():pScene(0) {}
};

bool DeleteItemByEntryCB(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if(!row)
		return true;
	if(!param)
		return false;

	storeDeleteItembyEntry* del = (storeDeleteItembyEntry*)param;

	if(del->nCount <= 0)
		return false;

	Item item;
	GetItemData(row, item);
	if(item.dwEntry != del->dwEntry)
		return true;
	if(!del->byIncludeBind && item.byBind)
		return true;
	if(!del->byIncludeTimeout && item.dwUneffectTime != 0)
	{
		time_t now;
		::time(&now);
		if(now >= item.dwUneffectTime)
			return true;
	}

	if(del->nCount > item.wStack)
	{
		del->nCount -= item.wStack;
		del->pScene->ClearRow(row);
	}
	else
	{
		item.wStack -= del->nCount;
		del->nCount = 0;
	}

	SetSlotUpdate(del->pScene, del->self, del->byBagType, index);

	return (del->nCount == 0);
}

int DeleteItemByEntry(IGame* pScene, UI32 self, UI08 byBag, DWORD dwEntry, int nCount, UI08 byIncludeBind, UI08 byIncludeTimeout)
{
	const char* strTabName = GetBagTableName(byBag);
	if(strTabName == NULL)
		return 0;

	storeDeleteItembyEntry del;
	del.pScene = pScene;
	del.dwEntry = dwEntry;
	del.nCount = nCount;
	del.byIncludeBind = byIncludeBind;
	del.byIncludeTimeout = byIncludeTimeout;

	pScene->TraverseTable(self, strTabName, DeleteItemByEntryCB, &del, false);

	return 1;
}

int EquipItem(IGame* pScene, UI32 self, UI08 byBag, UI08 bySlot, UI08 byOnEquip)
{
	if(byBag == BAG_TYPE_BAG)
	{
		//装备上去
		if(!byOnEquip)
			return 0;

		Item itemBag;
		GetItemData(pScene, self, PROP_TABLE_BAG, bySlot, itemBag);
		if(itemBag.dwEntry == 0)
			return 0;
        UI08 byEquipType = GetItemEquipType(itemBag.dwEntry);
		if( byEquipType == 0 )
			return 0;

		UI08 byEquipSlot = byEquipType-1;

		Item itemEquip;

		GetItemData(pScene, self, PROP_TABLE_EQUIP, byEquipSlot, itemEquip);

		if(itemEquip.dwEntry != 0)
		{
			// 装备栏上有物品
			CalcEquipProperties(pScene, self, byEquipSlot, 0);

			itemEquip.bySlot = bySlot;

			SetItemData(pScene, self, PROP_TABLE_BAG, bySlot, &itemEquip);

		}
		else
		{
			pScene->ClearRow(self, PROP_TABLE_BAG, bySlot);
		}

		itemBag.bySlot = byEquipSlot;

		SetItemData(pScene, self, PROP_TABLE_EQUIP, byEquipSlot, &itemBag);

		CalcEquipProperties(pScene, self, byEquipSlot, 1);

		SetSlotUpdate(pScene, self, BAG_TYPE_BAG, bySlot);
		SetSlotUpdate(pScene, self, BAG_TYPE_EQUIP, byEquipSlot);

		return 1;
	}
	else
	{
		//卸载
		if(byOnEquip)
			return 0;

		if(GetBagFreeSlotCount(pScene, self, BAG_TYPE_BAG) < 1)
			return 0;

        UI08 byEquipType = bySlot+1;

        Item itemEquip;

		GetItemData(pScene, self, PROP_TABLE_EQUIP, bySlot, itemEquip);

		CalcEquipProperties(pScene, self, bySlot, 0);

		pScene->ClearRow(self, PROP_TABLE_EQUIP, bySlot);

		StoreItem(pScene, self, itemEquip);

		return 1;
	}
}

int UseItem(IGame* pScene, UI32 self, UI08 byBag, UI08 bySlot)
{
	return 1;
}

bool FillItemsNoSpaceCB(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if (!row)
		return true;

	vector<Item> &vecItems = *(vector<Item> *)param;

	Item item;
	GetItemData(row, item);

	// 查看该物品是否可堆叠
	int nMaxStack = GetMaxStack(item.dwEntry);

    // 检测堆叠量
	assert (item.wStack <= nMaxStack);

	if (nMaxStack < 2)
	{
		// 不可堆叠物品
		vecItems.push_back(item);
	}
	else
	{
		for(std::vector<Item>::iterator it = vecItems.begin(); it != vecItems.end(); it++)
		{
			Item& oldItem = *it;
			if(CanOverlay(oldItem, item))
			{
				int nMaxStack = GetMaxStack(oldItem.dwEntry);
				int nRemainStack = nMaxStack - oldItem.wStack;
				if(nRemainStack == 0)
					continue;

				if(nRemainStack >= item.wStack)
				{
					oldItem.wStack += nRemainStack;
					item.wStack = 0;
				}
				else
				{
					oldItem.wStack = nMaxStack;
					item.wStack -= nRemainStack;
				}
			}

			if(item.wStack == 0)
				break;
		}

		if(item.wStack != 0)
			vecItems.push_back(item);
	}

	return true;
}

bool SortBagCB( Item p1, Item p2 )
{
	int nType1 = GetItemType(p1.dwEntry);
	int nType2 = GetItemType(p2.dwEntry);
	if (nType1 != nType1)
		return nType1 - nType2;

	if(p1.dwEntry!= p2.dwEntry)
		return p1.dwEntry - p2.dwEntry;

	if(p1.byQuality != p2.byQuality)
		return p1.byQuality - p2.byQuality;

	if(p1.byBind != p2.byBind)
		return p1.byBind - p2.byBind;

	if(p1.wStack != p2.wStack)
		return p1.wStack - p2.wStack;

	return 1;
}

void SortBag(IGame* pScene, UI32 self, UI08 byBagType)
{
	if (!g_pGame)
		return;

	if(byBagType!=BAG_TYPE_BAG && byBagType != BAG_TYPE_STORE)
		return;

	const char* strTabName = GetBagTableName(byBagType);

	// 将数据导入内存
	vector<Item> vecItems;
	pScene->TraverseTable(self, strTabName, FillItemsNoSpaceCB, &vecItems, true);

	if (vecItems.size() == 0)
	{
		return;
	}

	// 排序
	sort(vecItems.begin(), vecItems.end(), SortBagCB);

	int nMaxSlot = get_bag_max_slot(pScene, self, byBagType);

	// 删除原背包所有数据
	for (int i=0; i < nMaxSlot; i++)
	{
		pScene->ClearRow(self, strTabName, i);
	}

	// 把排序后的数据插入到表中
	assert(CanStoreItems(pScene, self, vecItems));

	StoreItems(pScene, self, vecItems);
}

int ExtendBagSize(IGame* pScene, UI32 self, UI08 byBagType)
{
	if(byBagType != BAG_TYPE_BAG && byBagType != BAG_TYPE_STORE)
		return 0;

	const char* strTabName = GetBagTableName(byBagType);
	if(strTabName == 0)
		return 0;

	//判断有没有背包拓展符
	//
	int nExtendBagCount = 0;
	if(byBagType == BAG_TYPE_BAG)
	{
		nExtendBagCount = pScene->GetPropInt(self, PROP_EXTEND_BAG_COUNT);
		if(nExtendBagCount >= BAG_ENTEND_COUNT)
			return 0;
	}
	else if(byBagType == BAG_TYPE_STORE)
	{
		nExtendBagCount = pScene->GetPropInt(self, PROP_EXTEND_STORE_COUNT);
		if(nExtendBagCount >= STORE_ENTEND_COUNT)
			return 0;
	}

	//删除背包里面应该删除的物品

	//DeleteItemByEntry(pScene, self)

	int nOldCount = pScene->GetMaxRowCount(self, strTabName);

	int nNewCount = nOldCount += (BAG_COL_NUMBER * BAG_VER_NUMBER);

	pScene->SetMaxRowCount(self, strTabName, nNewCount);

	const char* strUpdateTabName = GetBagUpdateTableName(byBagType);

	assert(strUpdateTabName != 0);

	pScene->SetMaxRowCount(self, strUpdateTabName, nNewCount);

	return 1;
}

void FixEquip(IGame* pScene, UI32 self, UI08 byBagType, UI08 slot)
{

}

struct tagUpdateBagStruct
{
	IGame* 	pScene;
	UI32 	self;
	UI08	byBagType;
	std::vector<UI08>* vecDelete;
	std::vector<Item>* vecUpdate;

	tagUpdateBagStruct() : pScene(0), self(0){}
};

bool CheckUpdateItemCB(size_t index, CVarRow* & row, size_t colCount, void* param)
{
	if(!param)
		return false;

	tagUpdateBagStruct* traverse = (tagUpdateBagStruct*)param;
	if (!row)
	{
		if(row->varList[0].Type() == VARTYPE_INT)
		{
			int changed = row->varList[0].IntVal();
			if(changed)
			{
				// 序列化物品信息，发往客户端
				const char* strTabName = GetBagTableName(traverse->byBagType);
				Item item;
				GetItemData(traverse->pScene, traverse->self, strTabName, index, item);
				if(item.strGuid.length() == 0)
				{
					traverse->vecDelete->push_back(index);
				}
				else
				{
					traverse->vecUpdate->push_back(item);
				}
			}

			return true;
		}
	}

	return false;
}

void NotifyClientBagUpdate(IGame* pScene, UI32 self, UI08 byBagType, std::vector<UI08>& vecDelete, std::vector<Item>& vecUpdate)
{
	if(vecDelete.size() >0)
	{
		CMsgTyped packet;
		packet.SetInt(vecDelete.size());
		for(int i=0; i<vecDelete.size(); i++)
		{
			packet.SetInt(vecDelete[i]);
		}

		pScene->Custom(self, 1, &packet);
	}


	if(vecUpdate.size() >0)
	{
		CMsgTyped packet;
		packet.SetInt(vecUpdate.size());
		for(int i=0; i<vecUpdate.size(); i++)
		{
			Item& item = vecUpdate[i];
			SerialItemData(item, packet);
		}

		pScene->Custom(self, 1, &packet);
	}
}

void CheckBagUpdateByBagType(IGame* pScene, UI32 self, UI08 byBagType)
{
	std::vector<UI08> vecDelete;
	std::vector<Item> vecUpdate;

	tagUpdateBagStruct traverse;
	traverse.pScene = pScene;
	traverse.self = self;
	traverse.byBagType = byBagType
	traverse.vecDelete = &vecDelete;
	traverse.vecUpdate = &vecUpdate;

	const char* strTabName = GetBagTableName(byBagType);
	pScene->TraverseTable(self, strTabName, CheckUpdateItemCB, &traverse, true);
	ClearSlotUpdate(pScene, self, byBagType);
	NotifyClientBagUpdate(pScene, self, byBagType, vecDelete, vecUpdate);
}

void CheckBagUpdate(IGame* pScene, UI32 self)
{
	CheckBagUpdateByBagType(pScene, self, BAG_TYPE_EQUIP);
	CheckBagUpdateByBagType(pScene, self, BAG_TYPE_BAG);
	CheckBagUpdateByBagType(pScene, self, BAG_TYPE_STORE);
}
